/*******************************************************************************
 * Copyright (C), 200{x}, Borqs Tech. Co., Ltd.
 * File Name: 
 *     lapi_pid.c
 * Description: 
 *     lapi_pid implementation   
 * History:  
 *     Date          Author                         Comments
 *    -----------   ---------------------------    --------------------
 *    May-09-2008   ray.fan@borqs.com            Created
*******************************************************************************/
#include <unistd.h>
#include <sys/file.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

#include "lapi_comm.h"
#include "lapi_pid.h"

LAPI_INT32 lapi_read_pid(void)
{
    LAPI_INT32   pid;
    FILE*   file;

    if (!(file = fopen(LAPI_PID_FILE, "r")))
    {
        return 0;
    }

    fscanf(file, "%d", &pid);
    fclose(file);

    return pid;
}

LAPI_INT32 lapi_check_pid(void)
{
    LAPI_INT32   pid = lapi_read_pid();

    if ((!pid) || (pid == getpid()))
    {
        return 0;
    }

    if (kill(pid, 0) && (errno == ESRCH))
    {
        return 0;
    }

    return pid;
}

LAPI_INT32 lapi_save_pid(void)
{
    LAPI_INT32   fd;
    LAPI_INT32   pid;
    FILE*   file;

    if (((fd = open(LAPI_PID_FILE, O_RDWR | O_CREAT, 0644)) == -1) ||
            ((file = fdopen(fd, "r+")) == NULL))
    {
        fprintf(stderr, "Fail to open or create %s!", LAPI_PID_FILE);
        return 0;
    }

    if (flock(fd, LOCK_EX | LOCK_NB) == -1)
    {
        fscanf(file, "%d", &pid);
        fclose(file);
        fprintf(stderr, "Fail to lock, lock is held by pid %d!", pid);
        return 0;
    }

    pid = getpid();
    if (!fprintf(file, "%d\n", pid))
    {
        close(fd);
        fprintf(stderr, "Fail to write pid , %s.", strerror(errno));
        return 0;
    }

    fflush(file);

    if (flock(fd, LOCK_UN) == -1)
    {
        close(fd);
        fprintf(stderr, "Fail to unlock pidfile %s, %s.", LAPI_PID_FILE, strerror(errno));
        return 0;
    }

    close(fd);

    return pid;
}

void lapi_remove_pid(void)
{
    unlink(LAPI_PID_FILE);

    fprintf(stderr, "Remove pid file : %s.", LAPI_PID_FILE);

    return;
}

LAPI_INT32 lapi_pid_mutex(void)
{
    pid_t   me = getpid();
    pid_t   grp = getpgrp();

    if (grp == -1)
    {
        fprintf(stderr, "Fail to get process group id, errno is: %d, %s ", errno, strerror(errno));
        return -1;
    }

    if (me == -1)
    {
        fprintf(stderr, "Fail to get process id, errno is: %d, %s ", errno, strerror(errno));
        return -1;
    }

    if (grp == me)
    {
        switch (fork())
        {
        case 0:
            {
                break;
            }

        case -1:
            {
                fprintf(stderr, "Fail to fork a new process, errno is: %d, %s ", errno, strerror(errno));
                break;
            }

        default:
            {
                fprintf(stderr, "Parent process exit");
                exit(0);
            }
        }
    }

    if (!lapi_check_pid())
    {
        if (!lapi_save_pid())
        {
            fprintf(stderr, "Fail to write pid file : %s!", LAPI_PID_FILE);
            exit(-1);
        }
    }
    else
    {
        fprintf(stderr, "LAPI server has already been running!");
        exit(-1);
    }

    if (setsid() == -1)
    {
        fprintf(stderr, "Fail to set a new session, errno is: %d, %s ", errno, strerror(errno));
        return -1;
    }

    return 0;
}
